developmentor - a developer services company				  
				      Essential .NET Security
   Modules

COM

Estimated time for completion: 60 minutes


Goals of this exercise:

  • Deploy managed code in COM+
  • Secure a COM+ application using attributes
  • Practice good strong name key management techniques

Overview

RPC and DCOM will be with us for a long time, so it's important to understand the security model for these technologies. Until .NET Remoting has security built in, many companies will choose to stick with DCOM and COM+ to build distributed applications, even in managed code. This activity will walk you through building a managed COM+ server and securing it.


part 1- Building and running the sample

In this part, you'll familiarize yourself with a bit of existing code that you'll be moving to COM+.

steps:

  1. Open up the PetStore.sln file, and familiarize yourself with the contents. Note that there is a simple Pet Store object and a unit test that can be used to exercise that object.

  2. Build the solution and test it. Note that you do not yet have a distributed application - you're just creating objects locally and using them. Once you're satisfied that things are working properly, move on to the next step, where you will add support for COM+.


part 2- Adding COM+ support

In this part, you'll move the pet store object into COM+ to create a distributed application that uses DCOM.

steps:

  1. Give your assembly a strong name. This is required if you want COM+ support. Use the public key included with your lab (see the pubkey file). Turn on delay signing, and be sure to register the public key token for strong name verification skipping. If this all sounds like gobbledygook to you, here are the steps you need to follow:

    steps:

    1. Open up AssemblyInfo.cs and scroll down to the bottom of the file.

    2. Flip the AssemblyDelaySign argument from false to true.

    3. Set the AssemblyKeyFile argument to @"..\..\pubkey", which points to a file containing just a public key (no private key).

    4. From an administrative command prompt, run the following on the pubkey file:

      sn -t pubkey

      The 16 digit string that is printed is the public key token.

    5. Take the public key token and call sn again, registering this key for strong name validation skipping (your public key token might be different than the one I show below):

      sn -Vr *,6bd035643bf2d94c

      The *, indicates that all assemblies with this key should be allowed to run without validating the strong name signature. This technique is designed to be used by developers in the lab - don't ever do this sort of thing on a production machine.

  2. Add a reference to System.EnterpriseServices.dll, and add a using statement for the System.EnterpriseServices namespace.

  3. Derive the PetStore class from ServicedComponent. This is a very significant change, as it indicates that anyone who creates this component should get a proxy that routes all requests through the COM+ plumbing.

  4. Since you'll be running the pet store code as a daemon process, we need to modify our call to MessageBox.Show() so that it doesn't hang us in a noninteractive window station. To fix this, go to the _msg() method on the pet store and add one extra argument to MessageBox.Show(): MessageBoxOptions.ServiceNotification

  5. Open up AssemblyInfo.cs and add a using statement at the top:

    using System.EnterpriseServices;
    

    Add the following assembly level attributes to AssemblyInfo.cs:

    [assembly: ApplicationName("Pet Store")]
    [assembly: ApplicationActivation(ActivationOption.Server)]
    
  6. In AssemblyInfo.cs, change the AssemblyVersion from 1.0.* to 1.0.0.0. This will save you much pain. If you don't assign classid GUIDs to each of your serviced components, the system generates a GUID based on the name of your class and assembly (which includes the version number). If this GUID keeps changing (which is what happens each time you make a build), you'll totally hose your client during development. Another option is to use GuidAttribute to specify the GUID for each class manually.

  7. From an administrative command prompt, run regsvcs.exe on your pet store assembly:

    regsvcs petstore.exe

    This adds it to the COM+ catalog. Note that you should do this everytime you rebuild the server assembly (petstore.exe).

  8. Run the Component Services explorer as administrator (%WINDIR%\system32\com\comexp.msc), then drill down into the list of COM+ applications on your computer. You should see an application called "Pet Store" - that's us! Right click the app and choose the Identity tab. Set the identity to Local Service so your code runs as a daemon with low privilege, and say OK.

  9. From a normal command prompt, try running the unit tests again. They should still work, although you may notice a wee bit of a delay as you're doing inter-process communication now. You should see a copy of dllhost.exe running as LOCAL SERVICE if you run task manager. That's the pet store.


part 3- Securing your COM+ application

Now it's time to add security. We'll do this by adding some new attributes that will require authentication, integrity, confidentiality, and authorization.

steps:

  1. Add the following assembly level attribute:

    [assembly: ApplicationAccessControl(true,
      Authentication     = AuthenticationOption.Privacy,
      ImpersonationLevel = ImpersonationLevelOption.Identify,
      AccessChecksLevel  = AccessChecksLevelOption.ApplicationComponent)]
    

    The first argument turns on access checks, and the AccessChecksLevel setting indicates that we want to perform checks at both the process level and the component level (this is required if you want to have any sort of fine-grained role-based checks, say on individual classes, interfaces, or methods). The Authentication setting indicates we want an authentication level of PKT_PRIVACY, which means the server won't accept unauthenticated requests (this actually does not cover the NULL session, which is pretty lame, but we'll fix that with our authorization settings shortly). Using Privacy also ensures message integrity checks and encryption for all payload in requests and responses to this app. Finally, the impersonation level setting just sets the default impersonation level for the app - remember this is a client-side setting, so it only affects outgoing COM calls made from the server (e.g., callbacks or calls to other mid tier servers).

  2. On the PetStore class, add the following attribute:

    [SecureMethod]

    This ensures that System.EnterpriseServices will make all calls to your class through the actual COM interface on which the method is defined. At this point you might be wondering "well, how else could the call be made?" It turns out that there's an undocumented interface called IRemoteDispatch which a managed client may use in some cases, and it doesn't hook into the COM+ role-based access checking logic. This attribute ensures this will never happen.

  3. Add a second attribute to the PetStore class:

    [ComponentAccessControl(true)]

    This is a very important step, because by default the component will have role-based checks disabled.

  4. Now add role-based authorization. You can do this by adding a SecurityRole attribute to any method, interface, or class that you'd like to restrict access to. Note that if you grant access to a class, you're granting access to all methods on the class. Same with an interface. We'll add method-level attributes to control access on a method-by-method basis.

    We want the following roles: Customers, Staff, and Owners. Customers should be able to buy and pet the animals, Staff should be allowed to feed them, and Owners can give away money. Here's an example of syntax:

    [SecurityRole("Customers")]
    void PetAnimal() { ... }
  5. Build your server and run regsvcs on it (as admin) to update the catalog.


part 4- Testing your COM+ server

Time to deploy!

steps:

  1. Try running your client now. It should fail miserably because you've turned on a bunch of access checks against roles, but you've not assigned any users into those roles. Let's remedy that.

  2. From the Component Services explorer, open the Pet Store application and drill down into the Roles folder. You should see the roles you specified, plus another one mysteriously entitled "Marshaler". Managed clients must be a member of the Marshaler role or they will have trouble getting access to the object, so add "Authenticated Users" to this role. Do the same thing for Customers, so any authenticated user will be considered a customer. This will keep NULL sessions out, because they lack the authenticated users SID. Finally, add a couple local accounts called Alice and Bob (for instance) and place one of these into the Staff role, and the other into the Owner role.

  3. Test again - you should now be able to pet and buy animals under your normal security context, but you won't be able to feed them or give away money.

  4. Run command prompts as Alice and Bob (or whatever you called your local accounts) and verify that they can access the server using whatever methods you authorized them to use.

Solutions: